package com.zjs.utils;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.Optional;
import java.util.function.Function;

/**
 * @author zhengJianSheng
 * @since 2023-12-03 13:36
 */
@Slf4j
public class ReflectionUtil {

    /**
     * 设置bean对象对应的值；值需要和字段类型一致或者常见的类型，不然会报错
     * @param bean 需要设置字段值的bean
     * @param field 字段对象
     * @param value 值
     * @return true: 成功; false: 失败
     */
    @SuppressWarnings("all")
    public static boolean setFieldValue(Object bean, Field field, Object value) {
        try {
            field.setAccessible(true);
            Class<?> type = field.getType();
            if (value == null || type == Object.class || type == value.getClass()) {
                field.set(bean, value);
            } else if (type.isInstance(value)) {
                field.set(bean, value);
            } else if (type == String.class) {
                field.set(bean, String.valueOf(value));
            } else if (type == Long.class || type == long.class) {
                field.set(bean, valueOf(value, Long::valueOf));
            } else if (type == Integer.class || type == int.class) {
                field.set(bean, valueOf(value, Integer::valueOf));
            } else if (type == Double.class || type == double.class) {
                field.set(bean, valueOf(value, Double::valueOf));
            } else if (type == Float.class || type == float.class) {
                field.set(bean, valueOf(value, Float::valueOf));
            } else if (type == Short.class || type == short.class) {
                field.set(bean, valueOf(value, Short::valueOf));
            } else if (type == Byte.class || type == byte.class) {
                field.set(bean, valueOf(value, Byte::valueOf));
            } else if (type == Character.class || type == char.class) {
                field.set(bean, valueOf(value, Byte::valueOf));
            } else if (type == Date.class) {
                field.set(bean, valueOf(value, DateUtil::parseDate));
            } else if (type == Boolean.class || type == boolean.class) {
                field.set(bean, valueOf(value, Boolean::valueOf));
            } else {
                log.error("BeanDealUtil.setFieldValue --> {}类{}字段不能匹配上类型，字段类型: {}，值类型：{}", bean.getClass().getName(), field, type.getName(), value.getClass().getName());
                return false;
            }
            return true;
        } catch (IllegalAccessException e) {
            log.error(String.format("%s类【%s】字段设置值【%s】失败：%s", bean.getClass().getName(), field.getName(), value, e.getMessage()), e);
            return false;
        }
    }

    /**
     * 转换值，解决值为字符串为空字符串的问题
     * @param value     值
     * @param valueOfFn 转换值函数
     * @return  转换之后的值
     */
    private static<T> T valueOf(Object value, Function<String, T> valueOfFn) {
        String valueStr = getValueToString(value);
        return Optional.ofNullable(valueStr).map(valueOfFn).orElse(null);
    }
    /**
     * 将值转为字符串，如果为空字符串，则当成null处理
     * @param value     值
     * @return  转换之后值对应的字符串
     */
    private static String getValueToString(Object value) {
        String valueStr = value.toString();
        if (StringUtils.isBlank(valueStr)) {
            return null;
        }
        return valueStr;
    }

    public  static <T> T getFieldValue(Class<?> clazz, Object bean, String field) {
        try {
            Field fieldObj = clazz.getDeclaredField(field);
            fieldObj.setAccessible(true);
            return (T)fieldObj.get(bean);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error(field + "字段找不到：" + e.getMessage(), e);
            return null;
        }
    }

}
